package com.javaee.weixin.util;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;

import com.javaee.weixin.Configure;
import com.javaee.weixin.entity.AccessToken;
import com.javaee.weixin.entity.Singleton;
import com.javaee.weixin.entity.Ticket;

import net.sf.json.JSONObject;

/**
 * 获取通用数据的工具类
 * 
 */
public class CommonDataUtils {

  /**
   * 返回普通AccessToken实体
   * 
   * @return AccessToken的对象
 * @throws Exception 
   */
  public static OAuth2AccessToken getOAuth2AccessToken(String code) throws Exception {
    // 接口调用请求参数集合
    Map<String, Object> requestParamMap = new HashMap<String, Object>();
    requestParamMap.put("grant_type", "authorization_code");
    requestParamMap.put("appid", Configure.APP_ID);
    requestParamMap.put("secret", Configure.APP_SECRET);
    requestParamMap.put("code", code);

    // 先判断是否已经失效
    Singleton singleton = Singleton.getInstance();
    Map<String, Object> map = singleton.getMap();

    OAuth2AccessToken accessToken = (OAuth2AccessToken) map.get("oAuth2AccessToken_" + code);

    long timestamp = new Date().getTime() / 1000;
    // 第一次获取普通access_token或者已经失效，则重新请求普通access_token
    if (accessToken == null || timestamp - accessToken.getTimestamp() > accessToken.getExpiresIn()) {
      // API地址回包数据
      String responseText = formUpload(Configure.I_access_token, requestParamMap);
      JSONObject jsonObject = JSONObject.fromObject(responseText);
      accessToken = new OAuth2AccessToken();
      accessToken.setCode(code);
      if(!jsonObject.containsKey("access_token")){
    	  throw new Exception("access_token not exsite : "+ responseText);
      }
	      accessToken.setAccessToken(jsonObject.getString("access_token"));
	      accessToken.setOpenId(jsonObject.getString("openid"));
	      accessToken.setExpiresIn(jsonObject.getInt("expires_in") - 200);
	      map.put("oAuth2AccessToken_" + code, accessToken);
      
    }
    return accessToken;
  }

  /**
   * 返回普通AccessToken实体
   * 
   * @return AccessToken的对象
   */
  public static AccessToken getAccessToken(String appId, String appSecret) {
    String tmpAppId = StringUtils.isBlank(appId) ? Configure.APP_ID : appId;
    String tepAppSecret = StringUtils.isBlank(appSecret) ? Configure.APP_SECRET : appSecret;
    // 接口调用请求参数集合
    Map<String, Object> requestParamMap = new HashMap<String, Object>();
    requestParamMap.put("grant_type", "client_credential");
    requestParamMap.put("appid", tmpAppId);
    requestParamMap.put("secret", tepAppSecret);
    // 先判断是否已经失效
    Singleton singleton = Singleton.getInstance();
    Map<String, Object> map = singleton.getMap();
    AccessToken accessToken = (AccessToken) map.get("accessToken_"+tmpAppId);
    long timestamp = new Date().getTime() / 1000;
    // 第一次获取普通access_token或者已经失效，则重新请求普通access_token
    if (accessToken == null || timestamp - accessToken.getTimestamp() > accessToken.getExpiresIn()) {
      // API地址回包数据
      String responseText = formUpload(Configure.I_token, requestParamMap);
      JSONObject jsonObject = JSONObject.fromObject(responseText);
      accessToken = new AccessToken();
      accessToken.setAccessToken(jsonObject.getString("access_token"));
      accessToken.setExpiresIn(jsonObject.getInt("expires_in") - 200);
      map.put("accessToken_"+tmpAppId, accessToken);
    }
    return accessToken;
  }

  /**
   * 返回Ticket实体
   * 
   * @return Ticket的对象
   */
  public static Ticket getTicket(String appId, String appSecret) {
    String tmpAppId = StringUtils.isBlank(appId) ? Configure.APP_ID : appId;
    // 接口调用请求参数集合
    Map<String, Object> requestParamMap = new HashMap<String, Object>();
    AccessToken accessToken = getAccessToken(tmpAppId, appSecret);
    
    requestParamMap.put("access_token", accessToken.getAccessToken());
    requestParamMap.put("type", "jsapi");
    // 先判断是否已经失效
    Singleton singleton = Singleton.getInstance();
    Map<String, Object> map = singleton.getMap();
    Ticket ticket = (Ticket) map.get("ticket_"+tmpAppId);
    long timestamp = new Date().getTime() / 1000;
    // 第一次获取ticket或者已经失效，则重新请求jsapi_ticket
    if (ticket == null || timestamp - ticket.getTimestamp() > ticket.getExpiresIn()) {
      // API地址回包数据
      String responseText = formUpload(Configure.I_ticket, requestParamMap);
      JSONObject jsonObject = JSONObject.fromObject(responseText);
      ticket = new Ticket();
      ticket.setTicket(jsonObject.getString("ticket"));
      ticket.setExpiresIn(jsonObject.getInt("expires_in") - 200);
      map.put("ticket_"+tmpAppId, ticket);
    }
    return ticket;
  }

  /**
   * 向微信发起请求
   * 
   * @param urlStr-微信接口地址
   * @param textMap-请求参数集合
   * @param fileMap
   * @return
   */
  public static String formUpload(String urlStr, Map<String, Object> textMap) {
    String res = "";
    HttpURLConnection conn = null;
    String BOUNDARY = "---------------------------123821742118716"; // boundary就是request头和上传文件内容的分隔符
    try {
      URL url = new URL(urlStr);
      conn = (HttpURLConnection) url.openConnection();
      conn.setConnectTimeout(5000);
      conn.setReadTimeout(30000);
      conn.setDoOutput(true);
      conn.setDoInput(true);
      conn.setUseCaches(false);
      conn.setRequestMethod("POST");
      conn.setRequestProperty("Connection", "Keep-Alive");
      conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN; rv:1.9.2.6)");
      conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);

      OutputStream out = new DataOutputStream(conn.getOutputStream());
      // text
      if (textMap != null) {
        // System.out.println(textMap);
        StringBuffer strBuf = new StringBuffer();
        Iterator iter = textMap.entrySet().iterator();
        while (iter.hasNext()) {
          Map.Entry entry = (Map.Entry) iter.next();
          String inputName = (String) entry.getKey();
          String inputValue = (String) entry.getValue();

          // System.out.println(inputValue);

          if (inputValue == null) {
            continue;
          }
          strBuf.append("\r\n").append("--").append(BOUNDARY).append("\r\n");
          strBuf.append("Content-Disposition: form-data; name=\"" + inputName + "\"\r\n\r\n");
          strBuf.append(inputValue);
        }
        out.write(strBuf.toString().getBytes());
      }
      byte[] endData = ("\r\n--" + BOUNDARY + "--\r\n").getBytes();
      out.write(endData);
      out.flush();
      out.close();

      // 读取返回数据
      StringBuffer strBuf = new StringBuffer();
      BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
      String line = null;
      while ((line = reader.readLine()) != null) {
        strBuf.append(line).append("\n");
      }
      res = strBuf.toString();
      reader.close();
      reader = null;
    } catch (Exception e) {
      System.out.println("发送POST请求出错。" + urlStr);
      e.printStackTrace();
    } finally {
      if (conn != null) {
        conn.disconnect();
        conn = null;
      }
    }
    return res;
  }

  /**
   * 发送https请求
   * 
   * @param requestUrl 请求地址
   * @param requestMethod 请求方式（GET、POST）
   * @param outputStr 提交的数据(xml)
   * @return 返回微信服务器响应的信息
   */
  public static String httpsRequest(String requestUrl, String requestMethod, String outputStr) {
    try {
      // 创建SSLContext对象，并使用我们指定的信任管理器初始化
      TrustManager[] tm = {new MyX509TrustManager()};
      SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
      sslContext.init(null, tm, new java.security.SecureRandom());
      // 从上述SSLContext对象中得到SSLSocketFactory对象
      SSLSocketFactory ssf = sslContext.getSocketFactory();
      URL url = new URL(requestUrl);
      HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
      conn.setSSLSocketFactory(ssf);
      conn.setDoOutput(true);
      conn.setDoInput(true);
      conn.setUseCaches(false);
      // 设置请求方式（GET/POST）
      conn.setRequestMethod(requestMethod);
      conn.setRequestProperty("content-type", "application/x-www-form-urlencoded");
      // 当outputStr不为null时向输出流写数据
      if (null != outputStr) {
        OutputStream outputStream = conn.getOutputStream();
        // 注意编码格式
        outputStream.write(outputStr.getBytes("UTF-8"));
        outputStream.close();
      }
      // 从输入流读取返回内容
      InputStream inputStream = conn.getInputStream();
      InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
      BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
      String str = null;
      StringBuffer buffer = new StringBuffer();
      while ((str = bufferedReader.readLine()) != null) {
        buffer.append(str);
      }
      // 释放资源
      bufferedReader.close();
      inputStreamReader.close();
      inputStream.close();
      inputStream = null;
      conn.disconnect();
      return buffer.toString();
    } catch (ConnectException ce) {
      ce.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }
    return null;
  }


}
